import { Component, ViewChild, TemplateRef, ViewContainerRef, ElementRef } from '@angular/core';
import { TemplatePortal } from '@angular/cdk/portal';
import { Overlay, OverlayConfig } from '@angular/cdk/overlay';
import { OverlayService, showItem } from '@iux/live';
import { Subject } from 'rxjs';
import { filter, takeUntil, tap } from 'rxjs/operators';
import { AnimationEvent } from '@angular/animations';

@Component({
  templateUrl: './user-defined.component.html',
  styles: [
    `
      .ui-overflow {
        width: 230px;
        margin-top: 4px;
        padding: 16px;
        border-radius: 8px;
        background: #ffffff;
        box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, 0.1);
      }

      .ui-overflow [lv-button] {
        float: right;
      }
    `,
  ],
  animations: [showItem],
})
export class UserDefinedComponent {
  constructor(private viewContainerRef: ViewContainerRef, private overlayService: OverlayService, private overlay: Overlay) { }

  overlayRef;
  // 动效
  animationState: 'showUp' | 'showDown' | 'hideUp' | 'hideDown' | 'void' = 'void';
  _direction: 'up' | 'down';
  open$ = new Subject<boolean>(); // 下拉面板展开收起流
  open: boolean = false; // 下拉面板展开状态
  private destroy$ = new Subject<void>();

  @ViewChild('template', { static: false }) template: TemplateRef<any>;
  @ViewChild('overlayBtn', { read: ElementRef, static: false }) overlayBtn: ElementRef<any>;

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }

  ngAfterViewInit(): void {
    this.subscribeOpenChange();
  }

  openPanel(): void {
    this.open$.next(true);
  }

  closePanel(): void {
    this.open$.next(false);
  }

  onAnimationDone(event: AnimationEvent): void {
    if ((event.fromState === 'showUp' && event.toState === 'hideUp') || (event.fromState === 'showDown' && event.toState === 'hideDown')) {
      this.open$.next(false);
    }
  }

  private openOverlay(): void {
    if (this.existOverlayRef()) {
      return;
    }
    const config = new OverlayConfig({
      hasBackdrop: false,
      positionStrategy: this.overlay
        .position()
        .flexibleConnectedTo(this.overlayBtn)
        .withPositions([
          {
            originX: 'start',
            originY: 'bottom',
            overlayX: 'start',
            overlayY: 'top',
          },
          {
            originX: 'start',
            originY: 'top',
            overlayX: 'start',
            overlayY: 'bottom',
          },
        ]),
    });
    const portal = new TemplatePortal(this.template, this.viewContainerRef);
    this.overlayRef = this.overlayService.open(portal, config, {
      afterOpen: (overlayRef) => {
        this.overlayRef = overlayRef;
        this.overlayRef.overlayRef._positionStrategy.positionChanges.subscribe(e => {
          const { originY } = e.connectionPair;
          if (originY === 'top') {
            this.animationState = 'showUp';
            this._direction = 'up';
          } else {
            this.animationState = 'showDown';
            this._direction = 'down';
          }
          this.open = true;
        });
      },
      beforeClose: () => new Promise(resolve => {
        if (this._direction === 'up') {
          this.animationState = 'hideUp';
        } else {
          this.animationState = 'hideDown';
        }
        const closeSubscribe = this.open$.subscribe(open => {
          if (!open) {
            closeSubscribe.unsubscribe();
            resolve();
          }
        });
      }),
      afterClose: () => {
        this.open = false;
      }
    });
  }

  private close(): void {
    this.existOverlayRef() && this.overlayRef.close();
  }

  private subscribeOpenChange() {
    this.open$
      .pipe(
        tap(res => {
          // 执行关闭
          if (!res) {
            this.close();
          }
        }),
        filter(res => res), // 过滤关闭状态，只执行打开
        takeUntil(this.destroy$)
      )
      .subscribe(() => this.openOverlay());
  }

  private existOverlayRef() {
    return this.overlayRef && this.overlayRef.overlayRef.hasAttached();
  }
}
